home *** CD-ROM | disk | FTP | other *** search
- <?php
-
- // +----------------------------------------------------------------------+
- // | PHP Version 4 |
- // +----------------------------------------------------------------------+
- // | Copyright (c) 2003-2005 Hermann Stainer, Web-Gear |
- // | http://www.web-gear.com/ |
- // | All rights reserved. |
- // +----------------------------------------------------------------------+
- // | DTA is a class that provides functions to create DTA files used in |
- // | Germany to exchange informations about money transactions with banks |
- // | or online banking programs. |
- // | This LICENSE is in the BSD license style. |
- // | |
- // | Redistribution and use in source and binary forms, with or without |
- // | modification, are permitted provided that the following conditions |
- // | are met: |
- // | |
- // | Redistributions of source code must retain the above copyright |
- // | notice, this list of conditions and the following disclaimer. |
- // | |
- // | Redistributions in binary form must reproduce the above copyright |
- // | notice, this list of conditions and the following disclaimer in the |
- // | documentation and/or other materials provided with the distribution. |
- // | |
- // | Neither the name of Hermann Stainer, Web-Gear nor the names of his |
- // | contributors may be used to endorse or promote products derived from |
- // | this software without specific prior written permission. |
- // | |
- // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
- // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
- // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
- // | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
- // | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
- // | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
- // | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
- // | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
- // | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
- // | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
- // | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
- // | POSSIBILITY OF SUCH DAMAGE. |
- // +----------------------------------------------------------------------+
- // | Author: Hermann Stainer <hs@web-gear.com> |
- // +----------------------------------------------------------------------+
- //
- // $Id: DTA.php,v 1.2.0 2005/01/25 15:00:00 hstainer Exp $
-
-
- /**
- * Determines the type of the DTA file:
- * DTA file contains credit payments.
- *
- * @const DTA_CREDIT
- */
- define("DTA_CREDIT", 0);
-
- /**
- * Determines the type of the DTA file:
- * DTA file contains debit payments (default).
- *
- * @const DTA_DEBIT
- */
- define("DTA_DEBIT", 1);
-
-
- /**
- * Dta class provides functions to create and handle with DTA files
- * used in Germany to exchange informations about money transactions with
- * banks or online banking programs.
- *
- * @author Hermann Stainer <hs@web-gear.com>
- * @version $Revision: 0.81 $
- * @since DTA 0.1
- */
- class DTA {
- /**
- * Type of DTA file, DTA_CREDIT or DTA_DEBIT.
- *
- * @var integer $type
- */
- var $type;
-
- /**
- * Account data for the file sender.
- *
- * @var integer $account_file_sender
- */
- var $account_file_sender;
-
- /**
- * Array of ASCII Codes of valid chars for DTA field data.
- *
- * @var array $validString_chars
- */
- var $validString_chars;
-
- /**
- * Current timestamp.
- *
- * @var integer $timestamp
- */
- var $timestamp;
-
- /**
- * Array of exchanges that the DTA file should contain.
- *
- * @var integer $exchanges
- */
- var $exchanges;
-
- /**
- * Constructor. The type of the DTA file must be set. One file can
- * only contain credits (DTA_CREDIT) OR debits (DTA_DEBIT).
- * This is a definement of the DTA format.
- *
- * @param integer $type Determines the type of the DTA file. Either DTA_CREDIT or DTA_DEBIT. Must be set.
- * @access public
- */
- function DTA($type)
- {
- $this->type = $type;
-
- $this->account_file_sender = array();
-
- $this->validString_chars = array(32, 36, 37, 38, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 196, 214, 220, 223);
-
- $this->timestamp = time();
-
- $this->exchanges = array();
- }
-
- /**
- * Checks if the given string contains only chars valid for fields in DTA files.
- *
- * @param string $string String that is checked.
- * @access public
- * @return boolean
- */
- function validString($string)
- {
- $occuring_chars = count_chars($string, 1);
-
- $result = true;
-
- foreach ($occuring_chars as $char_ord => $char_amount) {
- if (!in_array($char_ord, $this->validString_chars)) {
- $result = false;
- break;
- }
- }
-
- return $result;
- }
-
- /**
- * Makes the given string valid for DTA files. German umlauts become uppercase,
- * all other chars not allowed are replaced with space
- *
- * @param string $string String that should made valid.
- * @access public
- * @return string
- */
- function makeValidString($string)
- {
-
- $result = "";
-
- if (strlen($string) > 0) {
- $search = array(
- "'─'",
- "'╓'",
- "'▄'",
- "'Σ'",
- "'÷'",
- "'ⁿ'",
- "'▀'"
- );
-
- $replace = array(
- "Ae",
- "Oe",
- "Ue",
- "ae",
- "oe",
- "ue",
- "ss"
- );
-
- $result = strtoupper(preg_replace ($search, $replace, $string));
-
- for ($index = 0;$index < strlen($result);$index++) {
- if (!in_array(ord(substr($result, $index, 1)), $this->validString_chars)) {
- $result[$index] = " ";
- }
- }
- }
-
- return $result;
- }
-
- /**
- * Set the sender of the DTA file. Must be set for valid DTA file.
- * The given account data is also used as default sender's account.
- * Account data contains
- * name Sender's name. Maximally 27 chars are allowed.
- * bank_code Sender's bank code.
- * account_number Sender's account number.
- * additional_name If necessary, additional line for sender's name (maximally 27 chars).
-
- * @param array $account Account data fot file sender.
- * @access public
- * @return boolean
- */
- function setAccountFileSender($account)
- {
- if (strlen($account['name']) > 0 && is_numeric($account['bank_code']) && is_numeric($account['account_number'])) {
- if (empty($account['additional_name'])) {
- $account['additional_name'] = "";
- }
-
- $this->account_file_sender = array(
- "name" => substr($this->makeValidString($account['name']), 0, 27),
- "bank_code" => $account['bank_code'],
- "account_number" => $account['account_number'],
- "additional_name" => substr($this->makeValidString($account['additional_name']), 0, 27)
- );
-
- $result = true;
- } else {
- $result = false;
- }
-
- return $result;
- }
-
- /**
- * Adds an exchange. First the account data for the receiver of the exchange is set.
- * In the case the DTA file contains credits, this is the payment receiver. In the other
- * case (the DTA file contains debits), this is the account, from which money is taken away.
- * If the sender is not specified, values of the file sender are used by default.
- * Account data for receiver and sender contain
- * name Name. Maximally 27 chars are allowed.
- * bank_code Bank code.
- * account_number Account number.
- * additional_name If necessary, additional line for name (maximally 27 chars).
- *
- * @param array $account_receiver Receiver's account data.
- * @param double $amount Amount of money in this exchange. Currency: EURO
- * @param array $purposes Array of up to 15 lines (maximally 27 chars each) for description of the exchange.
- * @param array $account_sender Sender's account data.
- * @access public
- * @return boolean
- */
- function addExchange($account_receiver, $amount, $purposes, $account_sender = array())
- {
- if (empty($account_receiver['additional_name'])) {
- $account_receiver['additional_name'] = "";
- }
- if (empty($account_sender['name'])) {
- $account_sender['name'] = $this->account_file_sender['name'];
- }
- if (empty($account_sender['bank_code'])) {
- $account_sender['bank_code'] = $this->account_file_sender['bank_code'];
- }
- if (empty($account_sender['account_number'])) {
- $account_sender['account_number'] = $this->account_file_sender['account_number'];
- }
- if (empty($account_sender['additional_name'])) {
- $account_sender['additional_name'] = $this->account_file_sender['additional_name'];
- }
-
- if (strlen($account_sender['name']) > 0 && is_numeric($account_sender['bank_code']) && is_numeric($account_sender['account_number']) && strlen($account_receiver['name']) > 0 && is_numeric($account_receiver['bank_code']) && is_numeric($account_receiver['account_number']) && is_numeric($amount) && $amount > 0 && ((is_array($purposes) && count($purposes) >= 1) || (is_string($purposes) && strlen($purposes) > 0))) {
-
- $amount = round($amount * 100);
-
- if (is_string($purposes)) {
- $purposes = array($purposes, "");
- }
-
- $purposes_data = $purposes;
- $purposes = array();
-
- foreach ($purposes_data as $purpose) {
- $purposes[] = substr($this->makeValidString($purpose), 0, 27);
- }
-
- $this->exchanges[] = array(
- "sender_name" => substr($this->makeValidString($account_sender['name']), 0, 27),
- "sender_bank_code" => $account_sender['bank_code'],
- "sender_account_number" => $account_sender['account_number'],
- "sender_additional_name" => substr($this->makeValidString($account_sender['additional_name']), 0, 27),
- "receiver_name" => substr($this->makeValidString($account_receiver['name']), 0, 27),
- "receiver_bank_code" => $account_receiver['bank_code'],
- "receiver_account_number" => $account_receiver['account_number'],
- "receiver_additional_name" => substr($this->makeValidString($account_receiver['additional_name']), 0, 27),
- "amount" => $amount,
- "purposes" => $purposes
- );
-
- $result = true;
- } else {
- $result = false;
- }
-
- return $result;
- }
-
- /**
- * Returns the full content of the generated DTA file. All added exchanges are processed.
- *
- * @access public
- * @return string
- */
- function getFileContent()
- {
- $content = "";
-
- $sum_account_numbers = 0;
- $sum_bank_codes = 0;
- $sum_amounts = 0;
-
- /**
- * data record A
- */
-
- // record length (128 Bytes)
- $content .= str_pad ("128", 4, "0", STR_PAD_LEFT);
- // record type
- $content .= "A";
- // file mode (credit or debit)
- $content .= ($this->type == DTA_CREDIT) ? "G" : "L";
- // Customer File ("K") / Bank File ("B")
- $content .= "K";
- // sender's bank code
- $content .= str_pad ($this->account_file_sender['bank_code'], 8, "0", STR_PAD_LEFT);
- // only used if Bank File, otherwise NULL
- $content .= str_repeat ("0", 8);
- // sender's name
- $content .= str_pad ($this->account_file_sender['name'], 27, " ", STR_PAD_RIGHT);
- // date of file creation
- $content .= strftime("%d%m%y", $this->timestamp);
- // free (bank internal)
- $content .= str_repeat (" ", 4);
- // sender's account number
- $content .= str_pad ($this->account_file_sender['account_number'], 10, "0", STR_PAD_LEFT);
- // sender's reference number (optional)
- $content .= str_repeat ("0", 10);
- // free (reserve)
- $content .= str_repeat (" ", 15);
- // execution date ("DDMMYYYY", optional)
- $content .= str_repeat (" ", 8);
- // free (reserve)
- $content .= str_repeat (" ", 24);
- // currency (1 = Euro)
- $content .= "1";
-
- /**
- * data record(s) C
- */
-
- foreach ($this->exchanges as $exchange) {
- $sum_account_numbers += $exchange['receiver_account_number'];
- $sum_bank_codes += $exchange['receiver_bank_code'];
- $sum_amounts += $exchange['amount'];
-
- $additional_purposes = $exchange['purposes'];
- $first_purpose = array_shift($additional_purposes);
-
- $additional_parts = array();
-
- if (strlen($exchange['receiver_additional_name']) > 0) {
- $additional_parts[] = array("type" => "01",
- "content" => $exchange['receiver_additional_name']
- );
- }
-
- foreach ($additional_purposes as $additional_purpose) {
- $additional_parts[] = array("type" => "02",
- "content" => $additional_purpose
- );
- }
-
- if (strlen($exchange['sender_additional_name']) > 0) {
- $additional_parts[] = array("type" => "03",
- "content" => $exchange['sender_additional_name']
- );
- }
-
- $additional_parts_number = count($additional_parts);
- // record length (187 Bytes + 29 Bytes for each additional part)
- $content .= str_pad (187 + $additional_parts_number * 29, 4, "0", STR_PAD_LEFT);
- // record type
- $content .= "C";
- // first involved bank
- $content .= str_pad ($exchange['sender_bank_code'], 8, "0", STR_PAD_LEFT);
- // receiver's bank code
- $content .= str_pad ($exchange['receiver_bank_code'], 8, "0", STR_PAD_LEFT);
- // receiver's account number
- $content .= str_pad ($exchange['receiver_account_number'], 10, "0", STR_PAD_LEFT);
- // internal customer number (11 chars) or NULL
- $content .= "0" . str_repeat ("0", 11) . "0";
- // payment mode (text key)
- $content .= ($this->type == DTA_CREDIT) ? "51" : "05";
- // additional text key
- $content .= "000";
- // bank internal
- $content .= " ";
- // free (reserve)
- $content .= str_repeat ("0", 11);
- // sender's bank code
- $content .= str_pad ($exchange['sender_bank_code'], 8, "0", STR_PAD_LEFT);
- // sender's account number
- $content .= str_pad ($exchange['sender_account_number'], 10, "0", STR_PAD_LEFT);
- // amount
- $content .= str_pad ($exchange['amount'], 11, "0", STR_PAD_LEFT);
- // free (reserve)
- $content .= str_repeat (" ", 3);
- // receiver's name
- $content .= str_pad ($exchange['receiver_name'], 27, " ", STR_PAD_RIGHT);
- // delimitation
- $content .= str_repeat (" ", 8);
- // sender's name
- $content .= str_pad ($exchange['sender_name'], 27, " ", STR_PAD_RIGHT);
- // first line of purposes
- $content .= str_pad ($first_purpose, 27, " ", STR_PAD_RIGHT);
- // currency (1 = Euro)
- $content .= "1";
- // free (reserve)
- $content .= str_repeat (" ", 2);
- // amount of additional parts
- $content .= str_pad ($additional_parts_number, 2, "0", STR_PAD_LEFT);
-
- if (count($additional_parts) > 0) {
- for ($index = 1;$index <= 2;$index++) {
- if (count($additional_parts) > 0) {
- $additional_part = array_shift($additional_parts);
- } else {
- $additional_part = array("type" => " ",
- "content" => ""
- );
- }
- // type of addional part
- $content .= $additional_part['type'];
- // additional part content
- $content .= str_pad ($additional_part['content'], 27, " ", STR_PAD_RIGHT);
- }
- // delimitation
- $content .= str_repeat (" ", 11);
- }
-
- for ($part = 3;$part <= 5;$part++) {
- if (count($additional_parts) > 0) {
- for ($index = 1;$index <= 4;$index++) {
- if (count($additional_parts) > 0) {
- $additional_part = array_shift($additional_parts);
- } else {
- $additional_part = array("type" => " ",
- "content" => ""
- );
- }
- // type of addional part
- $content .= $additional_part['type'];
- // additional part content
- $content .= str_pad ($additional_part['content'], 27, " ", STR_PAD_RIGHT);
- }
- // delimitation
- $content .= str_repeat (" ", 12);
- }
- }
- }
-
- /**
- * data record E
- */
-
- // record length (128 bytes)
- $content .= str_pad ("128", 4, "0", STR_PAD_LEFT);
- // record type
- $content .= "E";
- // free (reserve)
- $content .= str_repeat (" ", 5);
- // number of records type C
- $content .= str_pad (count($this->exchanges), 7, "0", STR_PAD_LEFT);
- // free (reserve)
- $content .= str_repeat ("0", 13);
- // sum of account numbers
- $content .= str_pad ($sum_account_numbers, 17, "0", STR_PAD_LEFT);
- // sum of bank codes
- $content .= str_pad ($sum_bank_codes, 17, "0", STR_PAD_LEFT);
- // sum of amounts
- $content .= str_pad ($sum_amounts, 13, "0", STR_PAD_LEFT);
- // delimitation
- $content .= str_repeat (" ", 51);
-
- return $content;
- }
-
- /**
- * Writes the DTA file.
- *
- * @param string $filename Filename.
- * @access public
- * @return boolean
- */
- function saveFile($filename)
- {
- $content = $this->getFileContent();
-
- $Dta_fp = @fopen($filename, "w");
- if (!$Dta_fp) {
- $result = false;
- } else {
- $result = @fwrite($Dta_fp, $content);
- @fclose($Dta_fp);
- }
-
- return $result;
- }
- }
-
- ?>